import Foundation
import Vapor
import Redis

struct VerificationCodeService {
    // 验证码类型枚举
    enum VerificationType: String {
        case emailLogin = "email_login"
        case emailChange = "email_change"
        case phoneLogin = "phone_login"
        case phoneChange = "phone_change"
        case emailResetPassword = "email_reset_password"
        case phoneResetPassword = "phone_reset_password"
    }
    
    // 验证结果枚举
    enum VerificationResult {
        case success
        case invalidCode
        case expired
        
        var isSuccess: Bool {
            return self == .success
        }
        
        var errorMessage: String {
            switch self {
            case .success:
                return "验证成功"
            case .invalidCode:
                return "验证码错误，请重新输入"
            case .expired:
                return "验证码已过期，请重新获取"
            }
        }
    }
    
    // 6位数字验证码
    private let codeLength = 6
    // 验证码有效期10分钟
    private let codeExpiration: TimeAmount = .minutes(10)
    
    // 生成随机验证码
    func generateCode() -> String {
        var code = ""
        for _ in 1...codeLength {
            code += String(Int.random(in: 0...9))
        }
        return code
    }
    
    // 存储验证码
    func storeCode(for identifier: String, type: VerificationType, code: String, on req: Request) async throws {
        let redisKey = RedisKey("verification:\(type.rawValue):\(identifier)")
        let _ = req.redis.set(redisKey, to: code)
        let _ = req.redis.expire(redisKey, after: codeExpiration)
    }
    
    // 验证验证码，返回详细的验证结果
    func verifyCode(for identifier: String, type: VerificationType, code: String, on req: Request) -> EventLoopFuture<VerificationResult> {
        let keyIdentifier = identifier
        let keyType = type
        
        return req.redis.get(RedisKey("verification:\(type.rawValue):\(identifier)"), as: String.self).flatMap { storedCode in
            if let storedCode = storedCode {
                if storedCode == code {
                    // 验证成功，删除验证码
                    let deleteKey = RedisKey("verification:\(keyType.rawValue):\(keyIdentifier)")
                    return req.redis.delete(deleteKey).map { _ in
                        return .success
                    }
                } else {
                    // 验证码不匹配
                    return req.eventLoop.makeSucceededFuture(.invalidCode)
                }
            } else {
                // 验证码不存在或已过期
                return req.eventLoop.makeSucceededFuture(.expired)
            }
        }
    }
    
    // Redis 客户端不支持所有操作都返回 EventLoopFuture<T>类型 不可以直接参与 async/await
    func verifyCodeAsync(for identifier: String, type: VerificationType, code: String, on req: Request) async throws -> VerificationResult {
        return try await verifyCode(
            for: identifier,
            type: type,
            code: code,
            on: req
        ).get()
    }
    
    // 发送短信验证码
    func sendSMSCode(to phone: String, type: VerificationType, on req: Request) async throws -> String {
        // 生成验证码
        let code = generateCode()
        
        // 存储验证码
        try await storeCode(for: phone, type: type, code: code, on: req)
        
        // 检查是否是国际号码
        let isInternational = !phone.hasPrefix("+86") && phone.hasPrefix("+")
        
        // 使用腾讯云短信服务发送验证码
        try await req.application.tencentSMS.sendSMS(
            to: phone,
            code: code,
            international: isInternational
        )
        
        return code
    }
    
    // 发送邮箱验证码
    func sendEmailCode(email: String, type: VerificationType, req: Request) async throws -> String {
        // 生成6位数字验证码
        let code = generateCode()
        
        // 存储验证码
        try await storeCode(for: email, type: type, code: code, on: req)
        
        // 根据不同类型发送不同模板的邮件
        switch type {
        case .emailLogin:
            // 登录验证码邮件
            try await req.application.tencentEmail.sendLoginEmail(to: email, code: code)
        case .emailChange:
            // 邮箱绑定验证码邮件
            try await req.application.tencentEmail.sendBindEmailVerificationEmail(to: email, code: code)
        default:
            // 重置密码验证码邮件
            try await req.application.tencentEmail.sendResetPasswordEmail(to: email, code: code)
        }
        
        return code
    }
} 
